package com.xinyue.server.framework.handlermapping;

import com.xinyue.server.framework.common.GameFrameworkConfig;
import com.xinyue.server.framework.common.GameServerUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 游戏服务缓存管理类，主要负责缓存游戏中的连接及用户信息，方便快速获取,这里的缓存会依赖于连接的存在，如果连接断开了，会自动移除这里面的缓存
 *
 * @author 王广帅
 * @since 2022/1/3 16:52
 */

public class GameServerCacheService {
    private final static Logger logger = LoggerFactory.getLogger(GameServerCacheService.class);
    private final static AttributeKey<String> GAME_CHANNEL_USER_ID_ATTRIBUTE_KEY = AttributeKey.valueOf("game_channel_userId_attribute_key");
    /**
     * 用户的唯一id与对应的缓存信息
     */
    private Map<String, GameCacheModel> gameCacheModelMap = new ConcurrentHashMap<>(64);
    @Autowired
    private GameFrameworkConfig frameworkConfig;


    /**
     * 绑定连接通道与用户的关联关系，这样就可以实现通道与用户数据之间的相互查询，比如根据当前通道对象，获取对应用户数据或根据用户id获取对应的当前通道
     *
     * @param gameCacheModel 要绑定的数据对象
     * @return
     */
    public void bindChannel(GameCacheModel gameCacheModel) {
        ChannelHandlerContext ctx = gameCacheModel.getNettyCtx();
        Attribute<String> userAttr = ctx.channel().attr(GAME_CHANNEL_USER_ID_ATTRIBUTE_KEY);
        userAttr.set(gameCacheModel.getPlayerId());
        this.gameCacheModelMap.put(gameCacheModel.getPlayerId(), gameCacheModel);
        // 添加监听方法，当连接断开时，移除此处的缓存
        ctx.channel().closeFuture().addListener(future -> {
            logger.debug("连接断开，移除缓存,channelId:{}, playerId:{}", GameServerUtil.getChannelId(ctx.channel()), gameCacheModel.getPlayerId());
        });
    }

    public <T extends GameCacheModel> T getGameCacheModel(ChannelHandlerContext ctx) {
        Attribute<String> attr = ctx.channel().attr(GAME_CHANNEL_USER_ID_ATTRIBUTE_KEY);
        String playerId = attr.get();
        if (StringUtils.isEmpty(playerId)) {
            return null;
        }
        GameCacheModel gameCacheModel = this.gameCacheModelMap.get(playerId);
        if (gameCacheModel == null) {
            return null;
        }
        return (T) gameCacheModel;
    }

    /**
     * 从内存中查询GameChannel
     *
     * @param userId
     * @return
     */
    public GameCacheModel getGameChannel(String userId) {
        return this.gameCacheModelMap.get(userId);
    }
}
